package edu.columbia.plt.visage;

import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;

import javax.swing.JFrame;

import edu.columbia.plt.visage.interfaces.IMatrix;
import edu.columbia.plt.visage.interfaces.IMatrixDraw;


import java.awt.Color;
import java.awt.Shape;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Map;

public class MatrixDraw extends JFrame implements IMatrixDraw, MouseListener, KeyListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	Matrix matrix;
	//Plot plot;


	public MatrixDraw(String title, int width, int height) {
		
		super(title);
		setSize(width, height);
		setBackground(Color.WHITE);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
		addMouseListener(this);
		addKeyListener(this);
		//plot = new Plot();
	}

	
	/*
	 * (non-Javadoc)
	 * 
	 * @see visage.IMatrixDraw#redraw(Interfaces.IMatrix)
	 */
	public void redraw(Matrix matrix) {
		this.matrix = matrix;
		this.repaint();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see visage.IMatrixDraw#paint(java.awt.Graphics)
	 */
	public void paint(Graphics g) {
		if (matrix == null) {
			return;
		}

		// buffer the visual matrix, prevent flickering
		BufferedImage bimage = new BufferedImage(getWidth(), getHeight(),
				BufferedImage.TYPE_INT_ARGB);

		// turn on anti-aliasing for shapes
		RenderingHints renderHints = new RenderingHints(
				RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		renderHints.put(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY);

		Graphics2D g2 = bimage.createGraphics();
		g2.setRenderingHints(renderHints);
		g2.setBackground(Color.WHITE);

		// clear the visual matrix
		g2.clearRect(0, 0, super.getWidth(), super.getHeight());

		// get agent type counts and plot it
		
		
		for (Agent agent : Matrix.getAgentList()) {
			Shape agentOutline = null;
			if (agent.getShape() == Agent.Shape.CIRCLE) {
				agentOutline = new Ellipse2D.Double(agent.getX()*Matrix.getCellSize(),
						agent.getY()*Matrix.getCellSize(), agent.getSize() * 1.1, agent
								.getSize() * 1.1);
			} else if (agent.getShape() == Agent.Shape.SQUARE) {
				agentOutline = new Rectangle2D.Double(agent.getX()*Matrix.getCellSize(),
						agent.getY()*Matrix.getCellSize(), agent.getSize(), agent
								.getSize());
			} else if (agent.getShape() == Agent.Shape.TRIANGLE) {
				int size = (int) (agent.getSize() * 0.7);
				agentOutline = org.jfree.util.ShapeUtilities
						.createUpTriangle(size);
				agentOutline = org.jfree.util.ShapeUtilities
						.createTranslatedShape(agentOutline, agent
								.getX()*Matrix.getCellSize(), agent.getY()*Matrix.getCellSize());
			} else if (agent.getShape() == Agent.Shape.DIAMOND) {
				int size = (int) (agent.getSize() * 0.7);
				agentOutline = org.jfree.util.ShapeUtilities
						.createDiamond(size);
				agentOutline = org.jfree.util.ShapeUtilities
						.createTranslatedShape(agentOutline, agent
								.getX()*Matrix.getCellSize(), agent.getY()*Matrix.getCellSize());
			}

			// transparency
			AlphaComposite rule = AlphaComposite.getInstance(
					AlphaComposite.SRC_OVER, 0.75f);
			g2.setComposite(rule);

			g2.setColor(agent.getColor());
			g2.fill(agentOutline);
			
			
			
			if ( agent.track ) {
				
				List<Point> trackHistory = agent.getTrackHistory();
				if ( trackHistory == null || trackHistory.size() <= 1) 
					break;
				
				Point firstPoint = trackHistory.get(0);
				for ( int i = 1; i<trackHistory.size(); i++) {
					Point lastPoint = trackHistory.get(i);
					if (lastPoint.distance(firstPoint) <= Math.min(Matrix.getWidth()/2, Matrix.getHeight()/2)*Matrix.getCellSize()){
						g2.setColor(agent.getColor());
						//g2.drawLine(firstPoint.x*Matrix.getCellSize(), firstPoint.y*Matrix.getCellSize(), lastPoint.x*Matrix.getCellSize(), lastPoint.y*Matrix.getCellSize());
						g2.draw(new Line2D.Double(firstPoint, lastPoint));
					}
					firstPoint = lastPoint;
					
					
				}
			}
		}

		g2.dispose();
		g.drawImage(bimage, 0, 0, null);
	}

	
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	
	public void mouseClicked(MouseEvent e) {
		Matrix.setMouseClickedPoint(new Point(e.getX(), e.getY()));
		Matrix.mouseClickedSetTrue();
	}


	
	public void keyPressed(KeyEvent e) {
		switch(e.getKeyCode()) {
		case 65: 			// a
			Matrix.aPressedSetTrue();
			break;
		case 83:			// s
			Matrix.sPressedSetTrue();
			break;
		case 68:			// d
			Matrix.dPressedSetTrue();
			break;
		case 70:			// f
			Matrix.fPressedSetTrue();
			break;
		case 38:			// up
			Matrix.upPressedSetTrue();
			break;
		case 40:			// down
			Matrix.downPressedSetTrue();
			break;
		case 37:			// left
			Matrix.leftPressedSetTrue();
			break;
		case 39:			// right
			Matrix.rightPressedSetTrue();
			break;
			
		}
		
	}


	
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
	}


	
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}




}